package com.iwhale.sequence.redisidx.sequence;

import io.netty.buffer.ByteBufUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.redis.ArrayRedisMessage;
import io.netty.handler.codec.redis.ErrorRedisMessage;
import io.netty.handler.codec.redis.FullBulkStringRedisMessage;
import io.netty.handler.codec.redis.RedisMessage;
import io.netty.util.CharsetUtil;
import io.netty.util.ReferenceCountUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.ConcurrentHashMap;

public class InHandler extends ChannelInboundHandlerAdapter {
    private static Logger logger = LoggerFactory.getLogger(InHandler.class);

    // 序列列表
    private static final ConcurrentHashMap<String, Sequence> sequenceMap = new ConcurrentHashMap<>();

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        logger.info("客户端：{}接入！", ctx.channel().remoteAddress());
        super.channelActive(ctx);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        ArrayRedisMessage message = (ArrayRedisMessage) msg;
        RedisMessage response = processCMD(ctx, message);
        ctx.writeAndFlush(response);
        ReferenceCountUtil.release(message);
    }

    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        logger.error("异常【{}】:{}", ctx.channel().remoteAddress(), cause.getMessage());
    }

    /**
     * 指令处理
     *
     * @param ctx
     * @param message
     * @return
     */
    private RedisMessage processCMD(ChannelHandlerContext ctx, ArrayRedisMessage message) {
        String type = ((FullBulkStringRedisMessage) message.children().get(0)).content().toString(CharsetUtil.UTF_8);
        try {
            if ("sequence".equalsIgnoreCase(type)) {
                if (message.children().size() == 2) {
                    String seqName = ((FullBulkStringRedisMessage) message.children().get(1)).content().toString(CharsetUtil.UTF_8);
                    long seq = getSeq(seqName);
                    return new FullBulkStringRedisMessage(ByteBufUtil.writeUtf8(ctx.alloc(), String.valueOf(seq)));
                }
                else {
                    // redis通常的错误信息格式
                    return new ErrorRedisMessage("wrong number of arguments for 'sequence' command");
                }
            }
            else {
                // redis通常的错误信息格式
                return new ErrorRedisMessage("unknown command '" + type + "'");
            }
        }
        catch (Exception e) {
            logger.info("系统异常！", e);
            return new ErrorRedisMessage("系统异常");
        }
    }

    private long getSeq(String seqName) throws Exception {
        Sequence sequence = sequenceMap.computeIfAbsent(seqName, SequenceImpl::new);
        return sequence.nextVal();
    }
}
